package com.nowcoder.topic.string.middle;

/**
 * NC17 最长回文子串
 * @author d3y1
 */
public class NC17{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param A string字符串
     * @return int整型
     */
    public int getLongestPalindrome (String A) {
//        return solution1(A);
//        return solution2(A);
//        return solution3(A);
        return solution4(A);
    }

    /**
     * 滑动窗口
     * @param A
     * @return
     */
    private int solution1(String A){
        int len = A.length();
        for(int gap = len; gap > 0; gap--){
            for(int i = 0; i+gap <= len; i++){
                if(isPalindrome(A.substring(i, i+gap))){
                    return gap;
                }
            }
        }

        return 0;
    }

    /**
     * 是否回文串
     * @param sub
     * @return
     */
    private boolean isPalindrome(String sub){
        for(int i=0,j=sub.length()-1; i<j; i++,j--){
            if(sub.charAt(i) != sub.charAt(j)){
                return false;
            }
        }

        return true;
    }

    /**
     * 是否回文串
     * @param sub
     * @return
     */
    private boolean checkPalindrome(String sub){
        return sub.equals(new StringBuffer(sub).reverse().toString());
    }

    /**
     * 动态规划
     *
     * dp[i][j]表示子串[i,j](下标从0开始)是否为回文串(dp[i][j]=0: 非回文串 , dp[i][j]>0: 为回文串)
     *
     *          { = 0, 子串[i,j]非回文串
     * dp[i][j] {
     *          { > 0, 子串[i,j]为回文串 且长度为该值
     * @param A
     * @return
     */
    private int solution2(String A){
        char[] chars = A.toCharArray();
        int len = chars.length;

        int result = 1;
        int[][] dp = new int[len][len];
        for(int i = 0; i < len; i++){
            dp[i][i] = 1;
        }
        for(int i = 0; i+1 < len; i++){
            if(chars[i] == chars[i+1]){
                dp[i][i+1] = 2;
                result = 2;
            }
        }

        for(int gap = 2; gap < len; gap++){
            for(int i = 0; i+gap < len; i++){
                // 左右两边字符相同 且 之间子串为回文串
                if(chars[i]==chars[i+gap] && dp[i+1][i+gap-1]>0){
                    // 回文串 长度+2
                    dp[i][i+gap] = dp[i+1][i+gap-1] + 2;
                }else{
                    // 非回文串
                    dp[i][i+gap] = 0;
                }
                result = Math.max(result, dp[i][i+gap]);
            }
        }

        return result;
    }

    /**
     * 贪心: 中心扩展法
     * @param A
     * @return
     */
    private int solution3(String A){
        int result = 1;

        for(int i = 0; i+1 < A.length(); i++){
            result = Math.max(result, Math.max(spread(A,i,i), spread(A,i,i+1)));
        }

        return result;
    }

    /**
     * 中心扩展法: 分别向左右两边扩展
     * @param A
     * @param left
     * @param right
     * @return
     */
    private int spread(String A, int left, int right){
        while(0<=left && right<A.length() && A.charAt(left)==A.charAt(right)){
            left--;
            right++;
        }

        return right-left-1;
    }

    /**
     * Manacher算法
     * @return
     */
    private int solution4(String A){
        char[] mChars = manacher(A);
        int mCharsLen = mChars.length;
        // 回文半径
        int[] pRadius = new int[mCharsLen];
        int index = -1;
        // 之前已经遍历字符各回文半径最右侧再往右一位 -> 最右即将到达的位置
        int pRight = -1;
        int max = 1;
        for(int i = 0; i < mCharsLen; i++){
            pRadius[i] = pRight>i ? Math.min(pRadius[2*index-i], pRight-i) : 1;
            while(0<=i-pRadius[i] && i+pRadius[i]<mCharsLen){
                if(mChars[i-pRadius[i]] == mChars[i+pRadius[i]]){
                    pRadius[i]++;
                }else{
                    break;
                }
            }
            // pRight
            if(i+pRadius[i] > pRight){
                pRight = i+pRadius[i];
                index = i;
            }
            // 回文串长度 pRadius[i]-1
            max = Math.max(max, pRadius[i]-1);
        }

        return max;
    }

    /**
     * 字符串初始化处理: 奇回文串 和 偶回文串 方便统一处理
     *
     * bcbaa -> #b#c#b#a#a#
     * ba    -> #b#a#
     *
     * @param str
     * @return
     */
    private char[] manacher(String str){
        char[] chars = str.toCharArray();
        char[] result = new char[str.length()*2+1];

        int index = 0;
        for(int i = 0; i < result.length; i++){
            result[i] = (i&1)==0 ? '#' : chars[index++];
        }

        return result;
    }
}